PAM execution on logon
Why
During development of a project I wanted to be able to only allow a single logon through sFTP.
Every subsequent logons should fail.
Although there are different ways to achieve the same functionality, I wanted PAM to initiate the sFTP credential deletion.
Basic Idea
sFTP Logon with user + priv key
v
[PAM] User & key is valid
v
[PAM] Call script => remove public key
v
[PAM] Logon successful
What is PAM
GNU/Linux uses the Pluggable Authentication Modules (PAM) to handle authentication of different services.
All PAM applicable modules are stored under the path /etc/pam.d/.
If we take a look at the /etc/pam.d/sshd module we see the following calls to object libraries:
- Comments are removed
@include common-auth
account required pam_nologin.so
@include common-account
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so close
session required pam_loginuid.so
session optional pam_keyinit.so force revoke
@include common-session
session optional pam_motd.so motd=/run/motd.dynamic
session optional pam_motd.so noupdate
session optional pam_mail.so standard noenv # [1]
session required pam_limits.so
session required pam_env.so # [1]
session required pam_env.so user_readenv=1 envfile=/etc/default/locale
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so open
@include common-password
- Every "
session" runs a different action on the new session logon. sessionentries that have therequiredflag will hard fail and terminate the authentication.
Adding your own PAM module
- Needs sshd installed
Edit /etc/pam.d/sshd and append the following line right before @include common-passwod:
...
session required pam_exec.so seteuid /path/to/your/script.sh # << Add this line
@include common-password
seteuidwill instructpam_exec.soto run the script with the permissions of the logon user and populates PAM user variables.- Switch out
requirewithoptionalyou're testing.
Accessing variables
Now on every ssh logon PAM will execute the script.
Inside the script we can access individual variables to determine an action.
pam_exec.so populates the following variables:
PAM_RHOST=> IP of the remote hostPAM_RUSER=> Logon usernamePAM_SERVICE=> Service that PAM used (sshd/sudo/etc.)PAM_TTY=> path of the TTYPAM_TYPE=> contains eitheropen_sessionorclose_sessiondepending of the action.
This should now allow you to build a bash script to execute certain actions on specific service logons.
Example script
#!/bin/bash
if [ "$PAM_USER" == "user1" ] && [ "$PAM_TYPE" == "open_session" ]; then
# overwrite a key file
echo > /path/to/key
fi
Hardening SFTP
As a small tidbit here's a configuration how you can harden the sFTP logon:
ForceCommand internal-sftpforces ssh to load sftp-u 0666sets the default umask-p realpath,open,write,close,lstatblacklists the ftp commands
This allows the user1 to connect to sFTP and create files but not to download or read directory contents.
/etc/ssh/sshd_config.d/sftp.conf
Match User user1
ForceCommand internal-sftp -u 0666 -p realpath,open,write,close,lstat
AuthorizedKeysFile /path/to/keyfile
PubKeyAuthentication yes
PasswordAuthentication no
ChrootDirectory /path/to/chroot/dir
PermitTunnel no
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
Chroot permission issues
The ChrootDirectory needs to be owned by root and not writable by anybody else:
$ ls /path/to/chroot/dir
drwxr-xr-x 3 root root 4.0K Dec 20 00:00 .
SSHD will create it's own user directory in there so there is no need to create additional directories.